# game_engine/main.py - 修复导入版本
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
from pydantic import BaseModel
from typing import List, Dict, Optional
import asyncio
import json
import random
from datetime import datetime
from pathlib import Path
import sys
import os

# 修复导入路径 - 添加项目根目录到Python路径
sys.path.append('/app')

try:
    # 尝试绝对导入
    from game_state import GameWorld, FactorDevelopment, FactorType
except ImportError as e:
    print(f"导入错误: {e}")
    # 如果导入失败，使用模拟的类定义
    from enum import Enum
    
    class FactorType(Enum):
        MYDEI = "万敌"
        HYACINE = "风堇" 
        TRIBBIE = "缇宝"
        AGLAEA = "阿格莱雅"
        ANAXA = "那刻夏"
        CASTORICE = "遐蝶"
        CIPHER = "赛飞儿"
        HYSILENS = "海瑟音"
        CERYDRA = "刻律德菈"
        TERRAE = "丹恒腾荒"
        EVERNIGHT = "长夜月"
        PHAINON = "白厄"
    
    # 模拟其他必要的类
    class FactorDevelopment:
        def __init__(self, factor_type, name, spark_type):
            self.factor_type = factor_type
            self.name = name
            self.spark_type = spark_type
            self.level = 1
            self.current_location = (0.0, 0.0)
            self.is_alive = True
            self.attributes = {'health': 100}
    
    class GameWorld:
        def __init__(self):
            self.factors = []
            self.iron_curtain_progress = 0
            self.current_cycle = 0
        
        def add_factor(self, factor):
            self.factors.append(factor)

# 初始化FastAPI应用
app = FastAPI(title="Onpharos Game Engine")

# 配置路径
CONFIG_DIR = Path("/app/config")
LOGS_DIR = Path("/app/logs")
CONFIG_DIR.mkdir(exist_ok=True)
LOGS_DIR.mkdir(exist_ok=True)

# WebSocket连接管理
class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        if websocket in self.active_connections:
            self.active_connections.remove(websocket)

    async def send_personal_message(self, message: str, websocket: WebSocket):
        try:
            await websocket.send_text(message)
        except:
            self.disconnect(websocket)

    async def broadcast(self, message: dict):
        disconnected = []
        for connection in self.active_connections:
            try:
                await connection.send_json(message)
            except:
                disconnected.append(connection)
        
        for connection in disconnected:
            self.disconnect(connection)

manager = ConnectionManager()

# 训练服务API地址（容器间网络可直接用服务名访问）
TRAINING_SERVICE_URL = "http://onpharos-trainer:8000"

# 数据模型定义
class GameState(BaseModel):
    episode_id: str
    cycle: int
    turn: int
    agents: List[str]  # 参与的智能体列表
    agent_states: Dict[str, Dict]  # 智能体状态（生命值、能量等）
    world_state: Dict  # 地图、事件等全局状态

class ActionRequest(BaseModel):
    episode_id: str
    agent_id: str
    current_state: GameState

class ActionResponse(BaseModel):
    action: str  # 智能体动作（如"attack", "defend", "skill"）
    parameters: Dict  # 动作参数（如目标、技能ID等）
    confidence: float  # 动作置信度（0.0-1.0）

class EpisodeResult(BaseModel):
    episode_id: str
    winner: Optional[str]  # 获胜者（可为空）
    rewards: Dict[str, float]  # 各智能体奖励
    total_turns: int
    end_time: str

# 游戏引擎核心逻辑
class GameEngine:
    def __init__(self):
        self.active_episodes = {} # 存储当前活跃的episode: {episode_id: GameState}
        self.current_cycle = 0
        self.iron_curtain_progress = 0
        self.game_world = GameWorld()
        
        # 初始化12个因子
        self._initialize_factors()

    def _initialize_factors(self):
        """初始化12个因子"""
        factor_configs = [
            (FactorType.MYDEI, "万敌", "纷争"),
            (FactorType.HYACINE, "风堇", "天空"),
            (FactorType.TRIBBIE, "缇宝", "门径"),
            (FactorType.AGLAEA, "阿格莱雅", "浪漫"),
            (FactorType.ANAXA, "那刻夏", "理性"),
            (FactorType.CASTORICE, "遐蝶", "死亡"),
            (FactorType.CIPHER, "赛飞儿", "诡计"),
            (FactorType.HYSILENS, "海瑟音", "海洋"),
            (FactorType.CERYDRA, "刻律德菈", "律法"),
            (FactorType.TERRAE, "丹恒腾荒", "大地"),
            (FactorType.EVERNIGHT, "长夜月", "忘却"),
            (FactorType.PHAINON, "白厄", "负世")
        ]
        
        for factor_type, name, spark in factor_configs:
            factor = FactorDevelopment(factor_type, name, spark)
            factor.current_location = (
                float(random.randint(10, 90)),
                float(random.randint(10, 90))
            )
            self.game_world.add_factor(factor)
        
    # 添加新的API方法
    def get_detailed_status(self):
        """获取详细游戏状态"""
        return {
            "current_cycle": game_world.current_cycle,
            "current_time": game_world.current_time,
            "iron_curtain_progress": game_world.iron_curtain_progress,
            "active_factors_count": len([f for f in game_world.factors if f.is_alive]),
            "total_factors": len(game_world.factors),
            "lygus_health": game_world.lygus.health,
            "active_events": len([e for e in game_world.events if e.active]),
            "completed_events": len([e for e in game_world.events if e.completed])
        }
        
    def get_active_factors(self):
        """获取活跃因子列表"""
        factors_data = []
        for factor in game_world.factors:
            if factor.is_alive:
                factors_data.append({
                    "id": factor.name,
                    "name": factor.name,
                    "type": factor.factor_type.value,
                    "level": factor.level,
                    "health": factor.attributes['health'],
                    "max_health": 100 + (factor.level - 1) * 20,  # 估算最大生命值
                    "attack": factor.attributes['attack'],
                    "defense": factor.attributes['defense'],
                    "x": factor.current_location[0],
                    "y": factor.current_location[1],
                    "destination_x": factor.destination[0] if factor.destination else None,
                    "destination_y": factor.destination[1] if factor.destination else None,
                    "travel_progress": factor.travel_progress
                })
        return factors_data


    def load_world_rules(self):
        """加载游戏世界规则配置"""
        try:
            rule_path = CONFIG_DIR / "world_rules.json"
            if rule_path.exists():
                with open(rule_path, "r", encoding="utf-8") as f:
                    self.world_rules = json.load(f)
            else:
                # 默认规则
                self.world_rules = {
                    "max_turns": 50,
                    "reward_baseline": 100.0,
                    "agent_types": ["cipher", "hysilens", "cerydra", "terrae"]
                }
        except Exception as e:
            self.log_error(f"Failed to load world rules: {str(e)}")
            self.world_rules = {"max_turns": 50}

    def log_error(self, message: str):
        """记录错误日志"""
        log_path = LOGS_DIR / f"error_{datetime.now().strftime('%Y%m%d')}.log"
        with open(log_path, "a", encoding="utf-8") as f:
            f.write(f"[{datetime.now()}] {message}\n")

    async def generate_action(self, agent_id: str, state: GameState) -> ActionResponse:
        """生成智能体动作"""
        try:
            # 尝试调用训练服务获取动作
            response = requests.post(
                f"{TRAINING_SERVICE_URL}/agent/action",
                json={
                    "agent_id": agent_id,
                    "state": state.dict()
                },
                timeout=5
            )
            if response.ok:
                return ActionResponse(**response.json())
        except Exception as e:
            self.log_error(f"Failed to get action from training service: {str(e)}")
        
        # 降级：使用随机动作
        possible_actions = ["attack", "defend", "skill", "move"]
        action = random.choice(possible_actions)
        
        # 示例：攻击动作需要目标参数
        parameters = {}
        if action == "attack":
            # 选择除自身外的随机目标
            targets = [a for a in state.agents if a != agent_id]
            parameters["target"] = random.choice(targets) if targets else None
        
        return ActionResponse(
            action=action,
            parameters=parameters,
            confidence=round(random.uniform(0.7, 1.0), 2)
        )

    async def save_episode_result(self, result: EpisodeResult):
        """保存回合结果并同步到训练服务"""
        # 保存到本地日志
        result_path = LOGS_DIR / f"episode_{result.episode_id}.json"
        with open(result_path, "w", encoding="utf-8") as f:
            json.dump(result.dict(), f, ensure_ascii=False, indent=2)
        
        # 同步经验数据到训练服务
        try:
            # 这里简化处理，实际应包含完整的回合数据
            exp_data = {
                "episode_id": result.episode_id,
                "agent_actions": {},  # 实际应填充动作序列
                "rewards": result.rewards,
                "game_state": {}  # 实际应填充最终状态
            }
            response = requests.post(
                f"{TRAINING_SERVICE_URL}/experience/save",
                json=exp_data,
                timeout=10
            )
            if not response.ok:
                self.log_error(f"Failed to sync experience to training service: {response.text}")
        except Exception as e:
            self.log_error(f"Error syncing experience: {str(e)}")

# 初始化游戏引擎
game_engine = GameEngine()

# API端点定义
@app.get("/", response_model=Dict[str, str])
async def root():
    return {"message": "Game Engine service is running", "status": "healthy"}

@app.get("/health")
async def health_check():
    """健康检查端点"""
    return {
        "status": "healthy",
        "service": "game-engine",
        "timestamp": datetime.now().isoformat(),
        "active_episodes": len(game_engine.active_episodes),
        "factors_count": len(game_engine.game_world.factors)
    }

@app.get("/api/status")
async def get_api_status():
    """API状态（供React应用使用）"""
    return {
        "cycle": game_engine.current_cycle,
        "iron_curtain": game_engine.iron_curtain_progress,
        "training_status": "运行中" if game_engine.active_episodes else "已停止",
        "factors_count": len(game_engine.game_world.factors),
        "active_connections": len(manager.active_connections)
    }

@app.post("/episode/start", response_model=GameState)
async def start_episode(agents: List[str]):
    """启动新的游戏回合"""
    episode_id = f"ep_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{random.randint(1000, 9999)}"
    
    initial_state = GameState(
        episode_id=episode_id,
        cycle=game_engine.current_cycle,
        turn=1,
        agents=agents,
        agent_states={agent: {"hp": 100, "energy": 50} for agent in agents},
        world_state={"map": "default", "event": None}
    )
    
    game_engine.active_episodes[episode_id] = initial_state
    game_engine.current_cycle += 1
    
    # 广播新回合开始
    await manager.broadcast({
        "type": "episode_start",
        "episode_id": episode_id,
        "cycle": game_engine.current_cycle
    })
    
    return initial_state

@app.post("/agent/action", response_model=ActionResponse)
async def get_agent_action(request: ActionRequest):
    """获取智能体动作"""
    if request.episode_id not in game_engine.active_episodes:
        raise HTTPException(status_code=404, detail=f"Episode {request.episode_id} not found")
    
    return await game_engine.generate_action(request.agent_id, request.current_state)

@app.post("/episode/end", response_model=Dict[str, str])
async def end_episode(result: EpisodeResult):
    """结束回合并保存结果"""
    if result.episode_id not in game_engine.active_episodes:
        raise HTTPException(status_code=404, detail=f"Episode {result.episode_id} not found")
    
    # 更新游戏状态
    game_engine.iron_curtain_progress = min(100, game_engine.iron_curtain_progress + 5)
    
    # 广播回合结束
    await manager.broadcast({
        "type": "episode_end",
        "episode_id": result.episode_id,
        "winner": result.winner,
        "total_turns": result.total_turns
    })
    
    del game_engine.active_episodes[result.episode_id]
    return {"message": f"Episode {result.episode_id} ended successfully"}

@app.get("/episodes/active", response_model=List[str])
async def list_active_episodes():
    """列出当前活跃的回合"""
    return list(game_engine.active_episodes.keys())

@app.get("/game/status")
async def get_game_status():
    """返回游戏状态"""
    return {
        "active_episodes": len(game_engine.active_episodes),
        "current_cycle": game_engine.current_cycle,
        "iron_curtain_progress": game_engine.iron_curtain_progress,
        "factors_count": len(game_engine.game_world.factors),
        "status": "running"
    }

@app.get("/factors/active", response_model=List[Dict])
async def get_active_factors():
    """获取活跃因子列表"""
    return game_engine.get_active_factors()

@app.post("/game/advance", response_model=Dict)
async def advance_game_time(delta_time: float = 1.0):
    """推进游戏时间"""
    game_world.update_world(delta_time)
    return {
        "message": f"游戏时间推进了 {delta_time} 单位",
        "new_time": game_world.current_time,
        "events_triggered": len(game_world.game_log[-10:])  # 最近10条日志
    }

@app.post("/factor/create", response_model=Dict)
async def create_factor(factor_type: str, name: str):
    """创建新因子"""
    try:
        factor_enum = FactorType[factor_type.upper()]
        factor = FactorDevelopment(factor_enum, name, "")
        game_world.add_factor(factor)
        return {
            "message": f"成功创建因子 {name} ({factor_type})",
            "factor_id": name
        }
    except KeyError:
        raise HTTPException(status_code=400, detail=f"未知的因子类型: {factor_type}")
    
@app.get("/api/factors")
async def get_factors():
    """获取因子数据"""
    factors_data = []
    for factor in game_engine.game_world.factors:
        factors_data.append({
            "name": factor.name,
            "type": factor.factor_type.value,
            "level": factor.level,
            "health": factor.attributes.get('health', 100),
            "x": factor.current_location[0],
            "y": factor.current_location[1],
            "alive": factor.is_alive
        })
    
    return factors_data

@app.get("/events/active", response_model=List[Dict])
async def get_active_events():
    """获取活跃事件"""
    active_events = []
    for event_name, event in game_world.titan_events.items():
        if event.active:
            active_events.append({
                "name": event.name,
                "location": event.location,
                "start_time": event.start_time,
                "duration": event.duration,
                "description": event.description
            })
    return active_events

# WebSocket端点
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        # 发送初始状态
        await websocket.send_json({
            "type": "system_status",
            "cycle": game_engine.current_cycle,
            "iron_curtain": game_engine.iron_curtain_progress,
            "training_status": "运行中" if game_engine.active_episodes else "已停止",
            "active_connections": len(manager.active_connections)
        })
        
        # 定期发送状态更新
        while True:
            await asyncio.sleep(2)  # 每2秒发送一次更新
            
            # 更新游戏状态
            game_engine.iron_curtain_progress = min(100, game_engine.iron_curtain_progress + 0.1)
            
            # 发送系统状态
            await websocket.send_json({
                "type": "system_status",
                "cycle": game_engine.current_cycle,
                "iron_curtain": round(game_engine.iron_curtain_progress, 1),
                "training_status": "运行中" if game_engine.active_episodes else "已停止",
                "active_connections": len(manager.active_connections)
            })
            
            # 发送因子数据
            factors_data = []
            for factor in game_engine.game_world.factors:
                # 模拟因子状态变化
                if factor.is_alive and random.random() < 0.05:  # 5%概率受伤
                    factor.attributes['health'] = max(0, factor.attributes.get('health', 100) - random.uniform(1, 10))
                    if factor.attributes['health'] <= 0:
                        factor.is_alive = False
                
                factors_data.append({
                    "name": factor.name,
                    "type": factor.factor_type.value,
                    "level": factor.level,
                    "health": factor.attributes.get('health', 100),
                    "x": factor.current_location[0] + random.uniform(-1, 1),  # 模拟移动
                    "y": factor.current_location[1] + random.uniform(-1, 1),
                    "alive": factor.is_alive
                })
            
            await websocket.send_json({
                "type": "factor_update",
                "factors": factors_data
            })
            
    except WebSocketDisconnect:
        manager.disconnect(websocket)
    except Exception as e:
        print(f"WebSocket error: {e}")
        manager.disconnect(websocket)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8001)